#pragma once

#include <Preprocessor.h>
#include <glm/glm.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <memory>
namespace Umikaze::Core {

class Material;
class Geometry;
class Buffer;
class Object {
  CORE_OBJECT
public:
  Object(const glm::vec3 &position = glm::vec3(0.0f),
         const glm::vec3 &rotation = glm::vec3(0.0f),
         const glm::vec3 &scale = glm::vec3(1.0f));

  Object(const std::shared_ptr<Geometry> &geometry,
         const std::shared_ptr<Material> &material,
         const glm::vec3 &position = glm::vec3(0.0f),
         const glm::vec3 &rotation = glm::vec3(0.0f),
         const glm::vec3 &scale = glm::vec3(1.0f));

  glm::vec3 getPosition() const { return _position; }
  glm::vec3 getRotation() const { return _rotation; }

  void setPosition(const glm::vec3 &position) {
    _position = position;
    _dirty = true;
  }

  void setPosition(float x, float y, float z) {
    _position.x = x;
    _position.y = y;
    _position.z = z;
    _dirty = true;
  }

  void setRotation(float x, float y, float z) {
    _rotation.x = x;
    _rotation.y = y;
    _rotation.z = z;
    _dirty = true;
  }

  void draw(const std::shared_ptr<Buffer> &cameraBuffer);

  void drawDepth(const std::shared_ptr<Buffer> &cameraBuffer);

  void drawMotionVector(const std::shared_ptr<Buffer> &cameraBuffer,
                        const glm::mat4 &oldView, const glm::mat4 &oldProj);

  void drawShadow(const glm::mat4 &lightSpaceMatrix);

  void drawShadowCascade(const std::shared_ptr<Buffer> &lightSpaceMatrices,
                         uint32_t matrixCount);

  void rotate();

  void translate(float x, float y, float z);

  void translate(const glm::vec3 &t);

private:
  glm::mat4 genModelMatrix();

  glm::vec3 _position;
  glm::vec3 _rotation;
  glm::vec3 _scale;

  glm::mat4 _oldMatrix;
  glm::mat4 _newMatrix;

  bool _dirty = false;

  std::shared_ptr<Material> _material;
  std::shared_ptr<Geometry> _geometry;
};

} // namespace Umikaze::Core